package com.action.gulimall.seckill.schedul;

import com.action.gulimall.seckill.config.SeckillCommonConfig;
import com.action.gulimall.seckill.service.SeckillService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author sl shilun217@qq.com
 * @Deacription 定时提前上架秒杀商品
 * @date 2021/07/04/21:18
 **/
@Slf4j
@EnableScheduling
@Component
public class SeckillScheduls{

    @Autowired
    RedissonClient redissonClient;
    @Autowired
    SeckillService seckillService;

    /**
    * 定时提前将需要秒杀的商品和库存放到redis缓存中进行上架，加快查询速度
     *   每天凌晨0点，查询未来三天的需要秒杀的场次和商品信息，放入redis
     *   幂等 Redisson分布式锁保证分布式情况下只有一个任务执行 key=seckill:upload:lock
     *
     *   秒杀场次信息
     *   key=seckill:sessions:sntime:startTime_endTime  value=[skuId1,skuId2...]
     *   秒杀商品信息
     *   key=seckill:skus  key1=场次sessionId_skuId value1=商品JSON
     *   库存信号量   限流 商品需要有商品秒杀随机码 秒杀请求需要携带秒杀商品的随机码确保安全   商品库存量作为库存信号量数量，秒杀一次减一个信号量
     *   key=seckill:stock:随机码token  value=库存量
     *   需要加过期时间
     *   存入缓存的时候需要判断特点key是否存在，存在就不需要再放入了，因为已经上架过了
    * */
    //@Scheduled(cron = "* * 3 * * ?")
    @Scheduled(cron = "0 */1 * * * ?")
    public void seckillSkuUp(){
        RLock rLock = null;
        try{
            //获取分布式锁
            rLock = redissonClient.getLock(SeckillCommonConfig.SECKILL_UP_LOCK);
            rLock.lock(10, TimeUnit.SECONDS);
            //加载秒杀场次商品信息到redis缓存
            seckillService.upSeckillSessionWithSkusFuture3Days();
        }catch(Exception e){
            log.error("seckillSkuUp()任务执行出现异常", e);
        }finally {
            if(rLock!=null){
                rLock.unlock();
            }
        }
    }
}
